﻿using MathExp.Errors;
using System;
using System.Collections;
using System.Collections.Generic;

namespace MathExp
{
    public class Calculator
    {
        public Calculator()
        {
           // SymbolTable = new Dictionary<String, Decimal>();
        }
        public IDictionary<String, Decimal> SymbolTable { get; set; }

        public Calculator SetVar(String name, Decimal value)
        {
            if (SymbolTable == null) SymbolTable = new Dictionary<String, Decimal>();
            SymbolTable[name] = value;
            return this;
        }

        public decimal Calc(String expStr)
        {
            var parser = new Parser();
            var exp = parser.ParseExp(expStr);
            var convert = new MathConverter();
            var midExp = convert.convert(exp);
            return this.eval(midExp);
        }

        public Decimal eval(Object[] postfixExpr)
        {
            return eval(postfixExpr, 0, postfixExpr.Length);
        }

        public Decimal eval(Object[] postfixExpr, int offset, int len)
        {
            if (postfixExpr.Length - offset < len)
                throw new IllegalArgumentException();

            Stack stack = new Stack();
            int currPosition = offset;
            while (currPosition < offset + len)
            {
                Object element = postfixExpr[currPosition++];
                if (element is Decimal)
                {
                    stack.Push(element);
                }else if(element is String)
                {
                    stack.Push(element);
                }
                else if (element is Operator)
                {
                    Operator op = (Operator)element;
                    int dimensions = op.GetDimension();
                    if (dimensions < 1 || stack.Count < dimensions)
                        throw new IncalculableExpressionException("lack operand(s) for operator '" + op + "'");

                    Object[] operands = new Object[dimensions];
                    for (int j = dimensions - 1; j >= 0; j--)
                    {
                        operands[j] =stack.Pop();
                    }
                    stack.Push(op.Eval(operands, this.SymbolTable));
                }
                else
                    throw new IncalculableExpressionException("Unknown element: " + element);
            }
            if (stack.Count != 1)
                throw new IncalculableExpressionException("redundant operand(s)");

            return (Decimal)stack.Pop();
        }

    }
}
